package com.ruoyi.business.service.user.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.business.domain.entity.UserInfo;
import com.ruoyi.business.domain.entity.importExcel.DeviceImportRecord;
import com.ruoyi.business.domain.vo.user.UserInfoImportDTO;
import com.ruoyi.business.mapper.user.UserInfoMapper;
import com.ruoyi.business.service.user.IUserInfoService;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.framework.manager.AsyncManager;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.Date;
import java.util.ArrayList;
import java.util.List;
import java.util.TimerTask;

/*
* Service 业务处理层
* */
@Service
public class UserServiceImpl implements IUserInfoService {
    
    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserInfoMapper userInfoMapper;

    /*
    * 查询用户信息
    * @param id 主键
    * @return 用户信息
    * */
    @Override
    public UserInfo selectUserInfoById(Long id){
        log.debug("Selecting user info by id: {}", id);
        UserInfo userInfo = userInfoMapper.selectUserInfoById(id);
        log.debug("Found user info: {}", userInfo);
        return userInfo;
    }
    
    /*
    * 查询用户列表
    * @param userInfo 查询条件
    * @return 用户列表
    * */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<UserInfo> selectUserList(UserInfo userInfo){
        log.debug("Selecting user list with criteria: {}", userInfo);
        List<UserInfo> userList = userInfoMapper.selectUserInfoList(userInfo);
        log.debug("Found {} users", userList.size());
        return userList;
    }
    /*
    * 新增用户列表
    * */
    @Override
    public int insertUserInfo(UserInfo userInfo){
        checkIdCardUnique(userInfo.getIdCardNumber(),userInfo.getUserId());
        if (StrUtil.isEmpty(userInfo.getUserId())){
            userInfo.setUserId(IdUtils.fastUUID());
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        userInfo.setDeptId(StrUtil.isEmpty(userInfo.getDeptId())?String.valueOf(loginUser.getDeptId()):userInfo.getDeptId());
        userInfo.setCreateTime(DateUtils.getNowDate());
        return userInfoMapper.insertUserInfo(userInfo);
    }

    /*
    * 修改用户列表
    * */
    @Override
    public int updateUserInfo(UserInfo userInfo){
        // 验证userId不能为空
        if (StrUtil.isEmpty(userInfo.getUserId())) {
            throw new BaseException("用户ID不能为空");
        }
        checkIdCardUnique(userInfo.getIdCardNumber(),userInfo.getUserId());
        userInfo.setUpdateTime(DateUtils.getNowDate());
        return userInfoMapper.updateUserInfo(userInfo);
    }

    /*
    * 批量删除用户
    * */
    @Override
    public  int deleteUserInfoByIds(String[] userIds){
        return userInfoMapper.deleteUserInfoByIds(userIds);
    }

    /*
    * 根据userId删除用户
    * */
    @Override
    public int deleteUserInfoById(String userId){
        return userInfoMapper.deleteUserInfoById(userId);
    }

    /*
    *导出表格 查询用户列表
    * */
    @Override
    @DataScope(deptAlias = "d",userAlias = "u")
    public List<UserInfo> selectUserInfoList(UserInfo userInfo){
        return userInfoMapper.selectUserInfoList(userInfo);
    }


    /*
    * 导入用户列表
    * */
    /**
     * 导入用户列表
     *
     * 处理流程：
     * 1) 同步解析 Excel，读取“用户基本信息表”sheet 至内存
     * 2) 基础校验（必填、格式），若有错误直接抛出异常
     * 3) 生成记录 id 并异步处理入库，接口快速返回记录 id
     *
     * @param file       Excel 文件
     * @param taskSource 任务来源
     * @param fileName   文件名
     * @param userName   操作人
     * @return 记录 id
     */
    @Override
    public Long importUserInfoFromExcel(MultipartFile file,String taskSource,String fileName,String userName){
        try {
            // 在同步环境中先解析Excel文件，避免异步任务中临时文件被清理
            List<UserInfoImportDTO> guardianList = new ArrayList<>();
            try {
                // 使用Apache POI直接读取Excel文件
                Workbook workbook = WorkbookFactory.create(file.getInputStream());
                // 解析被监护人基本情况表
                try{
                    Sheet guardedSheet = workbook.getSheet("用户基本信息表");
                    if (guardedSheet != null){
                        guardianList = parseGuardedUserSheet(guardedSheet);
                    }
                }catch (Exception e){
                   log.warn("解析用户信息表失败"+e.getMessage());
                }
//                关闭workbook
                workbook.close();
            }catch (Exception e){
                throw new BaseException("解析Excel文件失败"+e.getMessage());
            }
            // 检查是否有数据
            if (guardianList.isEmpty() ){
                throw new BaseException("Excel文件中没有有效数据");
            }
            //验证必填字段
            List<String> validationErrors = new ArrayList<>();
            validateImportData(guardianList,validationErrors);
            if (!validationErrors.isEmpty()){
                throw new BaseException("数据验证失败,\n"+String.join("\n",validationErrors));
            }
            // 创建导入记录（验证通过后）
            DeviceImportRecord importRecord = new DeviceImportRecord();
            importRecord.setTaskSource(taskSource);
//            importRecord.setImportType("2"); // 2=用户导入
            importRecord.setImportFileName(fileName);
            int totalCount = guardianList.size();
            importRecord.setImportTotal((long)totalCount);
            importRecord.setSuccessNum(0L);
            importRecord.setFailNum(0L);
            importRecord.setTaskStatus("0");
            importRecord.setProgressPercent(new BigDecimal("0.00"));
            importRecord.setStartTime(DateUtils.getNowDate());
            importRecord.setCreateBy(userName);
            //保存导入记录
            Long recordId = System.currentTimeMillis();
            List<UserInfoImportDTO> fileGuardianList = new ArrayList<>(guardianList);
            AsyncManager.me().execute(new TimerTask() {
                @Override
                public void run() {
                    processUserImportWithData(fileGuardianList, recordId, userName);
                }
            });
            return recordId;
        }catch (Exception e){
            throw new BaseException("用户导入失败："+e.getMessage());
        }
    }



    /*
    * 检查身份证号是否唯一
    * */
    /**
     * 检查身份证号唯一性
     *
     * @param idCardNumber 身份证号
     * @param userId       用户唯一标识（更新场景用于排除自身）
     */
    private void checkIdCardUnique(String idCardNumber,String userId){
        if (StrUtil.isEmpty(idCardNumber)){
            return;
        }
        UserInfo checkUserInfo = new UserInfo();
        checkUserInfo.setIdCardNumber(idCardNumber);
        List<UserInfo> existUserInfo = userInfoMapper.selectUserInfoList(checkUserInfo);
        if (CollUtil.isNotEmpty(existUserInfo)){
            // 修改情况下，排除自己
            if (StrUtil.isNotEmpty(userId)){
                boolean hasOther = existUserInfo.stream()
                        .anyMatch(u -> !u.getUserId().equals(userId));
                if (hasOther){
                    throw new BaseException("身份证号已被其他用户使用，请检查");
                }
            }else {
                // 新增情况下
                throw new BaseException("身份证号已被使用，请检查");
            }
        }
    }

    /**
     * 解析“用户基本信息表”sheet
     */
    /**
     * 解析“用户基本信息表”sheet
     *
     * 列顺序：序号、姓名、性别、籍贯、民族、身份证号、出生日期、身高、体重、手机号、用户地址、备注
     *
     * @param sheet Excel 工作表
     * @return 解析后的导入 DTO 列表
     */
    private List<UserInfoImportDTO> parseGuardedUserSheet(Sheet sheet){
        List<UserInfoImportDTO> result = new ArrayList<>();
        if (sheet == null){
            return result;
        }
        int firstRowNum = sheet.getFirstRowNum();
        int lastRowNum = sheet.getLastRowNum();
        // 跳过表头，假定第一行为表头
        for (int rowIndex = firstRowNum + 1; rowIndex <= lastRowNum; rowIndex++){
            Row row = sheet.getRow(rowIndex);
            if (row == null){
                continue;
            }
            // 依据模板列顺序提取单元格
            UserInfoImportDTO dto = new UserInfoImportDTO();
            dto.setSerialNumber(getCellString(row, 0));
            dto.setUserName(getCellString(row, 1));
            dto.setGender(getCellString(row, 2));
            dto.setNativePlace(getCellString(row, 3));
            dto.setNation(getCellString(row, 4));
            dto.setIdCard(getCellString(row, 5));
            dto.setBirthDate(getCellString(row, 6));
            dto.setHeight(getCellString(row, 7));
            dto.setWeight(getCellString(row, 8));
            dto.setPhoneNumber(getCellString(row, 9));
            dto.setAddress(getCellString(row, 10));
            dto.setRemark(getCellString(row, 11));

            // 跳过完全空行
            if (StrUtil.isAllEmpty(dto.getUserName(), dto.getIdCard(), dto.getPhoneNumber())){
                continue;
            }
            result.add(dto);
        }
        return result;
    }

    /**
     * 将单元格转为字符串并去除首尾空白
     */
    private String getCellString(Row row, int cellIndex){
        Cell cell = row.getCell(cellIndex);
        if (cell == null){
            return null;
        }
        cell.setCellType(org.apache.poi.ss.usermodel.CellType.STRING);
        String value = cell.getStringCellValue();
        return StrUtil.isBlank(value) ? null : value.trim();
    }

    /**
     * 基础校验：必填、格式
     */
    /**
     * 基础校验：必填、性别/日期/数值格式
     *
     * @param data   导入数据
     * @param errors 错误集合（按行汇总）
     */
    private void validateImportData(List<UserInfoImportDTO> data, List<String> errors){
        if (CollUtil.isEmpty(data)){
            errors.add("没有可导入的数据");
            return;
        }
        int index = 2; // 从第2行起（表头为第1行）
        for (UserInfoImportDTO dto : data){
            List<String> rowErrors = new ArrayList<>();
            if (StrUtil.isBlank(dto.getUserName())){
                rowErrors.add("姓名为空");
            }
            if (StrUtil.isBlank(dto.getIdCard())){
                rowErrors.add("身份证号为空");
            }
            if (StrUtil.isNotBlank(dto.getGender())){
                String g = dto.getGender();
                if (!("男".equals(g) || "女".equals(g) || "M".equalsIgnoreCase(g) || "F".equalsIgnoreCase(g))){
                    rowErrors.add("性别取值不合法，应为男/女");
                }
            }
            if (StrUtil.isNotBlank(dto.getBirthDate())){
                Date bd = DateUtils.parseDate(dto.getBirthDate());
                if (bd == null){
                    rowErrors.add("出生日期格式错误");
                }
            }
            if (StrUtil.isNotBlank(dto.getHeight())){
                try { new BigDecimal(dto.getHeight()); } catch (Exception ex){ rowErrors.add("身高需为数字"); }
            }
            if (StrUtil.isNotBlank(dto.getWeight())){
                try { new BigDecimal(dto.getWeight()); } catch (Exception ex){ rowErrors.add("体重需为数字"); }
            }
            if (!rowErrors.isEmpty()){
                errors.add("第"+ index +"行："+ String.join("；", rowErrors));
            }
            index++;
        }
    }

    /**
     * 异步处理导入数据：去重、插入
     */
    /**
     * 异步处理导入数据：去重校验并插入
     *
     * @param data     导入数据
     * @param recordId 记录 id
     * @param userName 操作人
     */
    private void processUserImportWithData(List<UserInfoImportDTO> data, Long recordId, String userName){
        int success = 0;
        int fail = 0;
        for (UserInfoImportDTO dto : data){
            try {
                // 唯一性校验
                checkIdCardUnique(dto.getIdCard(), null);

                UserInfo entity = new UserInfo();
                entity.setUserId(IdUtils.fastUUID());
                entity.setUserName(dto.getUserName());
                // 性别映射
                String g = dto.getGender();
                if ("男".equals(g) || "M".equalsIgnoreCase(g)){
                    entity.setGender("M");
                } else if ("女".equals(g) || "F".equalsIgnoreCase(g)){
                    entity.setGender("F");
                }
                entity.setNativePlace(dto.getNativePlace());
                entity.setNation(dto.getNation());
                entity.setIdCardNumber(dto.getIdCard());
                if (StrUtil.isNotBlank(dto.getBirthDate())){
                    entity.setBirthDate(DateUtils.parseDate(dto.getBirthDate()));
                }
                if (StrUtil.isNotBlank(dto.getHeight())){
                    entity.setHeight(new BigDecimal(dto.getHeight()));
                }
                if (StrUtil.isNotBlank(dto.getWeight())){
                    entity.setWeight(new BigDecimal(dto.getWeight()));
                }
                entity.setPhoneNumber(dto.getPhoneNumber());
                entity.setAddress(dto.getAddress());
                entity.setRemark(dto.getRemark());
                entity.setUserType("0");

                // 部门信息：默认当前登录人部门
                try {
                    LoginUser loginUser = SecurityUtils.getLoginUser();
                    entity.setDeptId(String.valueOf(loginUser.getDeptId()));
                } catch (Exception ignore) { }

                entity.setCreateTime(DateUtils.getNowDate());
                userInfoMapper.insertUserInfo(entity);
                success++;
            }catch (Exception ex){
                log.warn("导入用户失败: {}", ex.getMessage());
                fail++;
            }
        }
        log.info("导入完成，记录id={}, 成功={}, 失败={}", recordId, success, fail);
    }

}
